﻿/* ================================================================================
<copyright file="ExtendedLogImplementation.cs" company="The Framework Factory, LLC" lastWriteTime="12/05/2012 23:23:47 PM">
  Copyright (c) 2012 The Framework Factory, LLC.  All rights reserved.
</copyright>
=================================================================================== */
using System;
using System.Globalization;
using System.Security.Principal;
using System.Threading;

using log4net;
using log4net.Core;
using log4net.Util;

namespace FWF.Logging
{
    /// <summary>
    /// A component that provides methods for logging other custom logging levels including Severe, Notice, Trace, and Verbose.
    /// </summary>
    public class ExtendedLogImplementation : LogImpl, IFWFLog
    {
        /*
        Emergency: 120000
        Fatal: 110000
        Alert: 100000
        Critical: 90000
        Severe: 80000
        Error: 70000
        Warn: 60000
        Notice: 50000
        Info: 40000
        Debug: 30000
        Fine: 30000
        Trace: 20000
        Finer: 20000
        Verbose: 10000
        Finest: 10000
        */
        /// <summary>
        /// 
        /// </summary>
        public readonly static Level Statistics = new Level( 5000, "STATS"  );

        private readonly static Type _declaringType = typeof( ExtendedLogImplementation );

        #region Constructors / Finalizer

        /// <summary>
        /// Initializes a new instance of the <see cref="ExtendedLogImplementation"/> class.
        /// </summary>
        /// <param name="logger">The logger to wrap.</param>
        /// <remarks>Construct a new wrapper for the specified logger.</remarks>
        public ExtendedLogImplementation( ILogger logger )
            : base( logger )
        {
        }

        #endregion

        #region IFWFLog Members

        /// <summary>
        /// Checks if this logger is enabled for the <see cref="Level.Notice"/> level.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this logger is enabled for <see cref="Level.Notice"/> events, <c>false</c> otherwise.
        /// </value>
        /// <remarks>
        ///   <para>
        /// This function is intended to lessen the computational cost of
        /// disabled log Notice statements.
        /// </para>
        ///   <para> For some ILog interface <c>log</c>, when you write:</para>
        ///   <code lang="C#">
        /// log.Notice("This is entry number: " + i );
        /// </code>
        ///   <para>
        /// You incur the cost constructing the message, string construction and concatenation in
        /// this case, regardless of whether the message is logged or not.
        /// </para>
        ///   <para>
        /// If you are worried about speed (who isn't), then you should write:
        /// </para>
        ///   <code lang="C#">
        /// if (log.IsNoticeEnabled)
        /// {
        /// log.Notice("This is entry number: " + i );
        /// }
        /// </code>
        ///   <para>
        /// This way you will not incur the cost of parameter
        /// construction if debugging is disabled for <c>log</c>. On
        /// the other hand, if the <c>log</c> is Notice enabled, you
        /// will incur the cost of evaluating whether the logger is Notice
        /// enabled twice. Once in <see cref="IsNoticeEnabled"/> and once in
        /// the <see cref="Notice(object)"/>.  This is an insignificant overhead
        /// since evaluating a logger takes about 1% of the time it
        /// takes to actually log. This is the preferred style of logging.
        /// </para>
        ///   <para>Alternatively if your logger is available statically then the is Notice
        /// enabled state can be stored in a static variable like this:
        /// </para>
        ///   <code lang="C#">
        /// private static readonly bool isNoticeEnabled = log.IsNoticeEnabled;
        /// </code>
        ///   <para>
        /// Then when you come to log you can write:
        /// </para>
        ///   <code lang="C#">
        /// if (isNoticeEnabled)
        /// {
        /// log.Notice("This is entry number: " + i );
        /// }
        /// </code>
        ///   <para>
        /// This way the Notice enabled state is only queried once
        /// when the class is loaded. Using a <c>private static readonly</c>
        /// variable is the most efficient because it is a run time constant
        /// and can be heavily optimized by the JIT compiler.
        /// </para>
        ///   <para>
        /// Of course if you use a static readonly variable to
        /// hold the enabled state of the logger then you cannot
        /// change the enabled state at runtime to vary the logging
        /// that is produced. You have to decide if you need absolute
        /// speed or runtime flexibility.
        /// </para>
        /// </remarks>
        /// <seealso cref="Notice(object)"/>
        public bool IsNoticeEnabled
        {
            get
            {
                return Logger.IsEnabledFor( Level.Notice );
            }
        }

        /// <summary>
        /// Checks if this logger is enabled for the <see cref="Level.Trace"/> level.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this logger is enabled for <see cref="Level.Trace"/> events, <c>false</c> otherwise.
        /// </value>
        /// <remarks>
        ///   <para>
        /// This function is intended to lessen the computational cost of
        /// disabled log Trace statements.
        /// </para>
        ///   <para> For some ILog interface <c>log</c>, when you write:</para>
        ///   <code lang="C#">
        /// log.Trace("This is entry number: " + i );
        /// </code>
        ///   <para>
        /// You incur the cost constructing the message, string construction and concatenation in
        /// this case, regardless of whether the message is logged or not.
        /// </para>
        ///   <para>
        /// If you are worried about speed (who isn't), then you should write:
        /// </para>
        ///   <code lang="C#">
        /// if (log.IsTraceEnabled)
        /// {
        /// log.Trace("This is entry number: " + i );
        /// }
        /// </code>
        ///   <para>
        /// This way you will not incur the cost of parameter
        /// construction if debugging is disabled for <c>log</c>. On
        /// the other hand, if the <c>log</c> is Trace enabled, you
        /// will incur the cost of evaluating whether the logger is Trace
        /// enabled twice. Once in <see cref="IsTraceEnabled"/> and once in
        /// the <see cref="Trace(object)"/>.  This is an insignificant overhead
        /// since evaluating a logger takes about 1% of the time it
        /// takes to actually log. This is the preferred style of logging.
        /// </para>
        ///   <para>Alternatively if your logger is available statically then the is Trace
        /// enabled state can be stored in a static variable like this:
        /// </para>
        ///   <code lang="C#">
        /// private static readonly bool isTraceEnabled = log.IsTraceEnabled;
        /// </code>
        ///   <para>
        /// Then when you come to log you can write:
        /// </para>
        ///   <code lang="C#">
        /// if (isTraceEnabled)
        /// {
        /// log.Trace("This is entry number: " + i );
        /// }
        /// </code>
        ///   <para>
        /// This way the Trace enabled state is only queried once
        /// when the class is loaded. Using a <c>private static readonly</c>
        /// variable is the most efficient because it is a run time constant
        /// and can be heavily optimized by the JIT compiler.
        /// </para>
        ///   <para>
        /// Of course if you use a static readonly variable to
        /// hold the enabled state of the logger then you cannot
        /// change the enabled state at runtime to vary the logging
        /// that is produced. You have to decide if you need absolute
        /// speed or runtime flexibility.
        /// </para>
        /// </remarks>
        /// <seealso cref="Trace(object)"/>
        public bool IsTraceEnabled
        {
            get
            {
                return Logger.IsEnabledFor( Level.Trace );
            }
        }

        /// <summary>
        /// Checks if this logger is enabled for the <see cref="Level.Verbose"/> level.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this logger is enabled for <see cref="Level.Verbose"/> events, <c>false</c> otherwise.
        /// </value>
        /// <remarks>
        ///   <para>
        /// This function is intended to lessen the computational cost of
        /// disabled log Verbose statements.
        /// </para>
        ///   <para> For some ILog interface <c>log</c>, when you write:</para>
        ///   <code lang="C#">
        /// log.Verbose("This is entry number: " + i );
        /// </code>
        ///   <para>
        /// You incur the cost constructing the message, string construction and concatenation in
        /// this case, regardless of whether the message is logged or not.
        /// </para>
        ///   <para>
        /// If you are worried about speed (who isn't), then you should write:
        /// </para>
        ///   <code lang="C#">
        /// if (log.IsVerboseEnabled)
        /// {
        /// log.Verbose("This is entry number: " + i );
        /// }
        /// </code>
        ///   <para>
        /// This way you will not incur the cost of parameter
        /// construction if debugging is disabled for <c>log</c>. On
        /// the other hand, if the <c>log</c> is Verbose enabled, you
        /// will incur the cost of evaluating whether the logger is Verbose
        /// enabled twice. Once in <see cref="IsVerboseEnabled"/> and once in
        /// the <see cref="Verbose(object)"/>.  This is an insignificant overhead
        /// since evaluating a logger takes about 1% of the time it
        /// takes to actually log. This is the preferred style of logging.
        /// </para>
        ///   <para>Alternatively if your logger is available statically then the is Verbose
        /// enabled state can be stored in a static variable like this:
        /// </para>
        ///   <code lang="C#">
        /// private static readonly bool isVerboseEnabled = log.IsVerboseEnabled;
        /// </code>
        ///   <para>
        /// Then when you come to log you can write:
        /// </para>
        ///   <code lang="C#">
        /// if (isVerboseEnabled)
        /// {
        /// log.Verbose("This is entry number: " + i );
        /// }
        /// </code>
        ///   <para>
        /// This way the Verbose enabled state is only queried once
        /// when the class is loaded. Using a <c>private static readonly</c>
        /// variable is the most efficient because it is a run time constant
        /// and can be heavily optimized by the JIT compiler.
        /// </para>
        ///   <para>
        /// Of course if you use a static readonly variable to
        /// hold the enabled state of the logger then you cannot
        /// change the enabled state at runtime to vary the logging
        /// that is produced. You have to decide if you need absolute
        /// speed or runtime flexibility.
        /// </para>
        /// </remarks>
        /// <seealso cref="Verbose(object)"/>
        public bool IsVerboseEnabled
        {
            get
            {
                return Logger.IsEnabledFor( Level.Verbose );
            }
        }

        /// <summary>
        /// Checks if this logger is enabled for the <see cref="Level.Severe"/> level.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this logger is enabled for <see cref="Level.Severe"/> events, <c>false</c> otherwise.
        /// </value>
        /// <remarks>
        ///   <para>
        /// This function is intended to lessen the computational cost of
        /// disabled log Severe statements.
        /// </para>
        ///   <para> For some ILog interface <c>log</c>, when you write:</para>
        ///   <code lang="C#">
        /// log.Severe("This is entry number: " + i );
        /// </code>
        ///   <para>
        /// You incur the cost constructing the message, string construction and concatenation in
        /// this case, regardless of whether the message is logged or not.
        /// </para>
        ///   <para>
        /// If you are worried about speed (who isn't), then you should write:
        /// </para>
        ///   <code lang="C#">
        /// if (log.IsSevereEnabled)
        /// {
        /// log.Severe("This is entry number: " + i );
        /// }
        /// </code>
        ///   <para>
        /// This way you will not incur the cost of parameter
        /// construction if debugging is disabled for <c>log</c>. On
        /// the other hand, if the <c>log</c> is Severe enabled, you
        /// will incur the cost of evaluating whether the logger is Severe
        /// enabled twice. Once in <see cref="IsSevereEnabled"/> and once in
        /// the <see cref="Severe(object)"/>.  This is an insignificant overhead
        /// since evaluating a logger takes about 1% of the time it
        /// takes to actually log. This is the preferred style of logging.
        /// </para>
        ///   <para>Alternatively if your logger is available statically then the is Severe
        /// enabled state can be stored in a static variable like this:
        /// </para>
        ///   <code lang="C#">
        /// private static readonly bool isSevereEnabled = log.IsSevereEnabled;
        /// </code>
        ///   <para>
        /// Then when you come to log you can write:
        /// </para>
        ///   <code lang="C#">
        /// if (isSevereEnabled)
        /// {
        /// log.Severe("This is entry number: " + i );
        /// }
        /// </code>
        ///   <para>
        /// This way the Severe enabled state is only queried once
        /// when the class is loaded. Using a <c>private static readonly</c>
        /// variable is the most efficient because it is a run time constant
        /// and can be heavily optimized by the JIT compiler.
        /// </para>
        ///   <para>
        /// Of course if you use a static readonly variable to
        /// hold the enabled state of the logger then you cannot
        /// change the enabled state at runtime to vary the logging
        /// that is produced. You have to decide if you need absolute
        /// speed or runtime flexibility.
        /// </para>
        /// </remarks>
        /// <seealso cref="Severe(object)"/>
        public bool IsSevereEnabled
        {
            get
            {
                return Logger.IsEnabledFor( Level.Severe );
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is statistics enabled.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is statistics enabled; otherwise, <c>false</c>.
        /// </value>
        public bool IsStatisticsEnabled
        {
            get
            {
                return Logger.IsEnabledFor( Statistics );
            }
        }

        /// <summary>
        /// Logs the specified logging event.
        /// </summary>
        /// <param name="loggingEventData">The logging event data.</param>
        public void Log( LoggingEventData loggingEventData )
        {
            loggingEventData = PrepareLoggingEventData( loggingEventData );

            Logger.Log( new LoggingEvent( loggingEventData ) );
        }

        /// <summary>
        /// Create a LoggingEvent component based upon the current context of the call.
        /// </summary>
        /// <returns></returns>
        public LoggingEventData PrepareLogEvent( Type declaringType )
        {
            if ( declaringType == null )
            {
                throw new ArgumentNullException( "declaringType" );
            }

            string logName = declaringType.FullName;

            var loggingEventData = new LoggingEventData();

            if ( logName.StartsWith( "FWF." ) )
            {
                // Replace the long "FWF." string with "FWF."
                logName = "FWF." + logName.Substring( "FWF.".Length );
            }

            loggingEventData.LoggerName = logName;
            loggingEventData.LocationInfo = new LocationInfo( declaringType );

            loggingEventData.TimeStamp = DateTime.Now;

            loggingEventData.Domain = AppDomain.CurrentDomain.FriendlyName;
            loggingEventData.ThreadName = Thread.CurrentThread.Name;

            WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();

            if ( windowsIdentity != null )
            {
                loggingEventData.Identity = windowsIdentity.Name;

                if ( windowsIdentity.User != null )
                {
                    loggingEventData.UserName = windowsIdentity.User.Value;
                }
            }

            loggingEventData.Properties = new PropertiesDictionary();
            loggingEventData.Properties[ "id" ] = -1;
            loggingEventData.Properties[ "instanceName" ] = GlobalContext.Properties[ "instanceName" ];
            loggingEventData.Properties[ "sessionName" ] = LogicalThreadContext.Properties[ "sessionName" ];
            loggingEventData.Properties[ "sessionContext" ] = LogicalThreadContext.Properties[ "sessionContext" ];
            loggingEventData.Properties[ "sessionId" ] = LogicalThreadContext.Properties[ "sessionId" ];

            loggingEventData.Properties[ "machineName" ] = Environment.MachineName;

            // FIX: Not sure the best way to handle this...
            //loggingEventData.Properties[ "exceptionType" ] = ExceptionType;

            //
            loggingEventData = PrepareLoggingEventData( loggingEventData );

            // These are expected to be updated by the implementation
            //loggingEventData.Level = Level.Alert;
            //loggingEventData.Message = "";
            //loggingEventData.ExceptionString = "";

            return loggingEventData;
        }

        /// <summary>
        /// Prepares the logging event data.
        /// </summary>
        /// <param name="loggingEventData">The logging event data.</param>
        /// <returns></returns>
        private LoggingEventData PrepareLoggingEventData( LoggingEventData loggingEventData )
        {
            if ( loggingEventData.Level == null )
            {
                loggingEventData.Level = Level.Debug;
            }
            if ( string.IsNullOrEmpty( loggingEventData.LoggerName ) )
            {
                loggingEventData.LoggerName = Logger.Name;
            }
            if ( loggingEventData.TimeStamp == DateTime.MinValue )
            {
                loggingEventData.TimeStamp = DateTime.Now;
            }

            if ( loggingEventData.Properties == null )
            {
                loggingEventData.Properties = new PropertiesDictionary();
            }
            if ( loggingEventData.LocationInfo == null )
            {
                loggingEventData.LocationInfo = new LocationInfo( "unknown", "unknown", "unknown", "1" );
            }

            if ( string.IsNullOrEmpty( loggingEventData.Message ) )
            {
                loggingEventData.Message = string.Empty;
            }
            if ( string.IsNullOrEmpty( loggingEventData.Domain ) )
            {
                loggingEventData.Domain = string.Empty;
            }
            if ( string.IsNullOrEmpty( loggingEventData.ExceptionString ) )
            {
                loggingEventData.ExceptionString = string.Empty;
            }
            if ( string.IsNullOrEmpty( loggingEventData.Identity ) )
            {
                loggingEventData.Identity = string.Empty;
            }
            if ( string.IsNullOrEmpty( loggingEventData.ThreadName ) )
            {
                loggingEventData.ThreadName = string.Empty;
            }
            if ( string.IsNullOrEmpty( loggingEventData.UserName ) )
            {
                loggingEventData.UserName = string.Empty;
            }

            return loggingEventData;
        }

        /// <summary>
        /// Log a message object with the <see cref="Level.Notice"/> level.
        /// </summary>
        /// <param name="message">The message object to log.</param>
        /// <overloads>Log a message object with the <see cref="Level.Notice"/> level.</overloads>
        /// <remarks>
        ///   <para>
        /// This method first checks if this logger is <c>Notice</c>
        /// enabled by comparing the level of this logger with the
        /// <see cref="Level.Notice"/> level. If this logger is
        /// <c>Notice</c> enabled, then it converts the message object
        /// (passed as parameter) to a string by invoking the appropriate
        /// <see cref="log4net.ObjectRenderer.IObjectRenderer"/>. It then
        /// proceeds to call all the registered appenders in this logger
        /// and also higher in the hierarchy depending on the value of
        /// the additivity flag.
        /// </para>
        ///   <para><b>WARNING</b> Note that passing an <see cref="Exception"/>
        /// to this method will print the name of the <see cref="Exception"/>
        /// but no stack trace. To print a stack trace use the
        /// <see cref="Notice(object,Exception)"/> form instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="Notice(object,Exception)"/>
        /// <seealso cref="IsNoticeEnabled"/>
        public void Notice( object message )
        {
            Logger.Log( _declaringType, Level.Notice, message, null );
        }

        /// <summary>
        /// Log a message object with the <see cref="Level.Notice"/> level including
        /// the stack trace of the <see cref="Exception"/> passed
        /// as a parameter.
        /// </summary>
        /// <param name="message">The message object to log.</param>
        /// <param name="exception">The exception to log, including its stack trace.</param>
        /// <remarks>
        /// See the <see cref="Notice(object)"/> form for more detailed information.
        /// </remarks>
        /// <seealso cref="Notice(object)"/>
        /// <seealso cref="IsNoticeEnabled"/>
        public void Notice( object message, Exception exception )
        {
            Logger.Log( _declaringType, Level.Notice, message, exception );
        }

        /// <summary>
        /// Logs a formatted message string with the <see cref="Level.Notice"/> level.
        /// </summary>
        /// <param name="format">A String containing zero or more format items</param>
        /// <param name="args">An Object array containing zero or more objects to format</param>
        /// <overloads>Log a formatted string with the <see cref="Level.Notice"/> level.</overloads>
        /// <remarks>
        ///   <para>
        /// The message is formatted using the <c>String.Format</c> method. See
        /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
        /// of the formatting.
        /// </para>
        ///   <para>
        /// This method does not take an <see cref="Exception"/> object to include in the
        /// log event. To pass an <see cref="Exception"/> use one of the <see cref="Notice(object,Exception)"/>
        /// methods instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="Notice(object)"/>
        /// <seealso cref="IsNoticeEnabled"/>
        public void NoticeFormat( string format, params object[] args )
        {
            if ( IsNoticeEnabled )
            {
                Logger.Log( _declaringType, Level.Notice, string.Format( CultureInfo.CurrentCulture, format, args ), null );
            }
        }

        /// <summary>
        /// Log a message object with the <see cref="Level.Trace"/> level.
        /// </summary>
        /// <param name="message">The message object to log.</param>
        /// <overloads>Log a message object with the <see cref="Level.Trace"/> level.</overloads>
        /// <remarks>
        ///   <para>
        /// This method first checks if this logger is <c>Trace</c>
        /// enabled by comparing the level of this logger with the
        /// <see cref="Level.Trace"/> level. If this logger is
        /// <c>Trace</c> enabled, then it converts the message object
        /// (passed as parameter) to a string by invoking the appropriate
        /// <see cref="log4net.ObjectRenderer.IObjectRenderer"/>. It then
        /// proceeds to call all the registered appenders in this logger
        /// and also higher in the hierarchy depending on the value of
        /// the additivity flag.
        /// </para>
        ///   <para><b>WARNING</b> Note that passing an <see cref="Exception"/>
        /// to this method will print the name of the <see cref="Exception"/>
        /// but no stack trace. To print a stack trace use the
        /// <see cref="Trace(object,Exception)"/> form instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="Trace(object,Exception)"/>
        /// <seealso cref="IsTraceEnabled"/>
        public void Trace( object message )
        {
            Logger.Log( _declaringType, Level.Trace, message, null );
        }

        /// <summary>
        /// Log a message object with the <see cref="Level.Trace"/> level including
        /// the stack trace of the <see cref="Exception"/> passed
        /// as a parameter.
        /// </summary>
        /// <param name="message">The message object to log.</param>
        /// <param name="exception">The exception to log, including its stack trace.</param>
        /// <remarks>
        /// See the <see cref="Trace(object)"/> form for more detailed information.
        /// </remarks>
        /// <seealso cref="Trace(object)"/>
        /// <seealso cref="IsTraceEnabled"/>
        public void Trace( object message, Exception exception )
        {
            Logger.Log( _declaringType, Level.Trace, message, exception );
        }

        /// <summary>
        /// Logs a formatted message string with the <see cref="Level.Trace"/> level.
        /// </summary>
        /// <param name="format">A String containing zero or more format items</param>
        /// <param name="args">An Object array containing zero or more objects to format</param>
        /// <overloads>Log a formatted string with the <see cref="Level.Trace"/> level.</overloads>
        /// <remarks>
        ///   <para>
        /// The message is formatted using the <c>String.Format</c> method. See
        /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
        /// of the formatting.
        /// </para>
        ///   <para>
        /// This method does not take an <see cref="Exception"/> object to include in the
        /// log event. To pass an <see cref="Exception"/> use one of the <see cref="Trace(object,Exception)"/>
        /// methods instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="Trace(object)"/>
        /// <seealso cref="IsTraceEnabled"/>
        public void TraceFormat( string format, params object[] args )
        {
            if ( IsTraceEnabled )
            {
                Logger.Log( _declaringType, Level.Trace, string.Format( CultureInfo.CurrentCulture, format, args ), null );
            }
        }

        /// <summary>
        /// Log a message object with the <see cref="Level.Verbose"/> level.
        /// </summary>
        /// <param name="message">The message object to log.</param>
        /// <overloads>Log a message object with the <see cref="Level.Verbose"/> level.</overloads>
        /// <remarks>
        ///   <para>
        /// This method first checks if this logger is <c>Verbose</c>
        /// enabled by comparing the level of this logger with the
        /// <see cref="Level.Verbose"/> level. If this logger is
        /// <c>Verbose</c> enabled, then it converts the message object
        /// (passed as parameter) to a string by invoking the appropriate
        /// <see cref="log4net.ObjectRenderer.IObjectRenderer"/>. It then
        /// proceeds to call all the registered appenders in this logger
        /// and also higher in the hierarchy depending on the value of
        /// the additivity flag.
        /// </para>
        ///   <para><b>WARNING</b> Note that passing an <see cref="Exception"/>
        /// to this method will print the name of the <see cref="Exception"/>
        /// but no stack Verbose. To print a stack Verbose use the
        /// <see cref="Verbose(object,Exception)"/> form instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="Verbose(object,Exception)"/>
        /// <seealso cref="IsVerboseEnabled"/>
        public void Verbose( object message )
        {
            Logger.Log( _declaringType, Level.Verbose, message, null );
        }

        /// <summary>
        /// Log a message object with the <see cref="Level.Verbose"/> level including
        /// the stack Verbose of the <see cref="Exception"/> passed
        /// as a parameter.
        /// </summary>
        /// <param name="message">The message object to log.</param>
        /// <param name="exception">The exception to log, including its stack Verbose.</param>
        /// <remarks>
        /// See the <see cref="Verbose(object)"/> form for more detailed information.
        /// </remarks>
        /// <seealso cref="Verbose(object)"/>
        /// <seealso cref="IsVerboseEnabled"/>
        public void Verbose( object message, Exception exception )
        {
            Logger.Log( _declaringType, Level.Verbose, message, exception );
        }

        /// <summary>
        /// Logs a formatted message string with the <see cref="Level.Verbose"/> level.
        /// </summary>
        /// <param name="format">A String containing zero or more format items</param>
        /// <param name="args">An Object array containing zero or more objects to format</param>
        /// <overloads>Log a formatted string with the <see cref="Level.Verbose"/> level.</overloads>
        /// <remarks>
        ///   <para>
        /// The message is formatted using the <c>String.Format</c> method. See
        /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
        /// of the formatting.
        /// </para>
        ///   <para>
        /// This method does not take an <see cref="Exception"/> object to include in the
        /// log event. To pass an <see cref="Exception"/> use one of the <see cref="Verbose(object,Exception)"/>
        /// methods instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="Verbose(object)"/>
        /// <seealso cref="IsVerboseEnabled"/>
        public void VerboseFormat( string format, params object[] args )
        {
            if ( IsVerboseEnabled )
            {
                Logger.Log( _declaringType, Level.Verbose, string.Format( CultureInfo.CurrentCulture, format, args ), null );
            }
        }

        /// <summary>
        /// Log a message object with the <see cref="Level.Severe"/> level.
        /// </summary>
        /// <param name="message">The message object to log.</param>
        /// <overloads>Log a message object with the <see cref="Level.Severe"/> level.</overloads>
        /// <remarks>
        ///   <para>
        /// This method first checks if this logger is <c>Severe</c>
        /// enabled by comparing the level of this logger with the
        /// <see cref="Level.Severe"/> level. If this logger is
        /// <c>Severe</c> enabled, then it converts the message object
        /// (passed as parameter) to a string by invoking the appropriate
        /// <see cref="log4net.ObjectRenderer.IObjectRenderer"/>. It then
        /// proceeds to call all the registered appenders in this logger
        /// and also higher in the hierarchy depending on the value of
        /// the additivity flag.
        /// </para>
        ///   <para><b>WARNING</b> Note that passing an <see cref="Exception"/>
        /// to this method will print the name of the <see cref="Exception"/>
        /// but no stack Severe. To print a stack Severe use the
        /// <see cref="Severe(object,Exception)"/> form instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="Severe(object,Exception)"/>
        /// <seealso cref="IsSevereEnabled"/>
        public void Severe( object message )
        {
            Logger.Log( _declaringType, Level.Severe, message, null );
        }

        /// <summary>
        /// Log a message object with the <see cref="Level.Severe"/> level including
        /// the stack Severe of the <see cref="Exception"/> passed
        /// as a parameter.
        /// </summary>
        /// <param name="message">The message object to log.</param>
        /// <param name="exception">The exception to log, including its stack Severe.</param>
        /// <remarks>
        /// See the <see cref="Severe(object)"/> form for more detailed information.
        /// </remarks>
        /// <seealso cref="Severe(object)"/>
        /// <seealso cref="IsSevereEnabled"/>
        public void Severe( object message, Exception exception )
        {
            Logger.Log( _declaringType, Level.Severe, message, exception );
        }

        /// <summary>
        /// Logs a formatted message string with the <see cref="Level.Severe"/> level.
        /// </summary>
        /// <param name="format">A String containing zero or more format items</param>
        /// <param name="args">An Object array containing zero or more objects to format</param>
        /// <overloads>Log a formatted string with the <see cref="Level.Severe"/> level.</overloads>
        /// <remarks>
        ///   <para>
        /// The message is formatted using the <c>String.Format</c> method. See
        /// <see cref="String.Format(string, object[])"/> for details of the syntax of the format string and the behavior
        /// of the formatting.
        /// </para>
        ///   <para>
        /// This method does not take an <see cref="Exception"/> object to include in the
        /// log event. To pass an <see cref="Exception"/> use one of the <see cref="Severe(object,Exception)"/>
        /// methods instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="Severe(object)"/>
        /// <seealso cref="IsSevereEnabled"/>
        public void SevereFormat( string format, params object[] args )
        {
            if ( IsSevereEnabled )
            {
                Logger.Log( _declaringType, Level.Severe, string.Format( CultureInfo.CurrentCulture, format, args ), null );
            }
        }

        /// <summary>
        /// Log a message object with the <see cref="Statistics"/> level.
        /// </summary>
        /// <param name="message">The message object to log.</param>
        /// <overloads>Log a message object with the <see cref="Level.Severe"/> level.</overloads>
        /// <remarks>
        ///   <para>
        /// This method first checks if this logger is <c>Severe</c>
        /// enabled by comparing the level of this logger with the
        /// <see cref="Level.Severe"/> level. If this logger is
        /// <c>Severe</c> enabled, then it converts the message object
        /// (passed as parameter) to a string by invoking the appropriate
        /// <see cref="log4net.ObjectRenderer.IObjectRenderer"/>. It then
        /// proceeds to call all the registered appenders in this logger
        /// and also higher in the hierarchy depending on the value of
        /// the additivity flag.
        /// </para>
        ///   <para><b>WARNING</b> Note that passing an <see cref="Exception"/>
        /// to this method will print the name of the <see cref="Exception"/>
        /// but no stack Severe. To print a stack Severe use the
        /// <see cref="Severe(object,Exception)"/> form instead.
        /// </para>
        /// </remarks>
        /// <seealso cref="Severe(object,Exception)"/>
        /// <seealso cref="IsSevereEnabled"/>
        public void Statistic( object message )
        {
            Logger.Log( _declaringType, Level.Severe, message, null );
        }

        /// <summary>
        /// Logs a formatted message string with the Statistic level.
        /// </summary>
        /// <param name="format">A String containing zero or more format items</param>
        /// <param name="args">An Object array containing zero or more objects to format</param>
        /// <seealso cref="Statistic(object)" />
        ///   <seealso cref="IsStatisticsEnabled" />
        /// <remarks>
        /// The message is formatted using the <c>String.Format</c> method. See
        /// <see cref="String.Format(string, object[])" /> for details of the syntax of the format string and the behavior
        /// of the formatting.
        /// </remarks>
        public void StatisticFormat( string format, params object[] args )
        {
            if ( IsStatisticsEnabled )
            {
                Logger.Log( _declaringType, Statistics, string.Format( CultureInfo.CurrentCulture, format, args ), null );
            }
        }

        /// <summary>
        /// Warns if.
        /// </summary>
        /// <param name="ifTrue">if set to <c>true</c> [if true].</param>
        /// <param name="message">The message.</param>
        public void WarnIf( bool ifTrue, string message )
        {
            if ( ifTrue )
            {
                Warn( message );
            }
        }

        #endregion

    }
}
